#pragma once
#include <queue>
#include <pthread.h>

#define DEFAULT_CAPACITY 10

template<typename T>
class BlockingQueue
{
public:
    BlockingQueue(const unsigned int capacity = DEFAULT_CAPACITY)
        :_capacity(capacity)
    {
        // 函数间相互调用可能会重复加锁
        pthread_mutexattr_t attr;
        pthread_mutexattr_init(&attr);
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);  // 设置为递归锁
        pthread_mutex_init(&_mutex, &attr);  // 用属性初始化互斥量
        pthread_mutexattr_destroy(&attr);  // 销毁属性对象

        pthread_cond_init(&_not_empty, nullptr);
        pthread_cond_init(&_not_full, nullptr);
    }

    void push(const T& data)
    {
        pthread_mutex_lock(&_mutex);
        while(full())
        {
            pthread_cond_wait(&_not_full, &_mutex);
        }
        _queue.push(data);
        pthread_cond_signal(&_not_empty);
        pthread_mutex_unlock(&_mutex);
    }

    T pop()
    {
        pthread_mutex_lock(&_mutex);
        while(empty())
        {
            pthread_cond_wait(&_not_empty, &_mutex);
        }
        T ret = _queue.front();
        _queue.pop();
        pthread_cond_signal(&_not_full);
        pthread_mutex_unlock(&_mutex);
        return ret;
    }

    unsigned int size()
    {
        pthread_mutex_lock(&_mutex);
        unsigned int size = _queue.size();
        pthread_mutex_unlock(&_mutex);
        return size;
    }

    bool empty()
    {
        pthread_mutex_lock(&_mutex);
        bool ret = _queue.empty();
        pthread_mutex_unlock(&_mutex);
        return ret;
    }

    bool full()
    {
        pthread_mutex_lock(&_mutex);
        bool ret = (_queue.size() == _capacity);
        pthread_mutex_unlock(&_mutex);
        return ret;
    }

    ~BlockingQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_not_empty);
        pthread_cond_destroy(&_not_full);
    }
private:
    std::queue<T> _queue;
    unsigned int _capacity;
    pthread_mutex_t _mutex;
    pthread_cond_t _not_empty;
    pthread_cond_t _not_full;
};